package com.bida.core.mongo;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

/**
 * This is where we define an abstract DAO class for MongoDB operations. The implementations are trivial, but
 * the method signatures conform to the standard definitions in BaseDao.
 * 
 * @param <T>
 */
public abstract class BaseMongodbDao<T> implements BaseDao<T> {

    /**
     * 获取需要操作的实体类class
     * 
     * @return
     */
    protected abstract Class<T> getEntityClass();

    /**
     * 获取主键字段名称，mongodb默认主键字段名称为"_id"
     * 
     * @return String
     */
    protected String getIdProName() {
        return "_id";
    }

    /**
     * 派生类设置该值
     */
    //@Autowired
    protected MongoTemplate mongoTemplate;

    public MongoTemplate getMongoTemplate() {
        return mongoTemplate;
    }

    public void setMongoTemplate(MongoTemplate mongoTemplate) {
        this.mongoTemplate = mongoTemplate;
    }
    
    public T selectOne(Map<String, Object> queryMap) {
        Query query = getQuery(queryMap);
        return mongoTemplate.findOne(query, this.getEntityClass());
    }

    public T selectById(String id) {
        Query query = new Query(Criteria.where(getIdProName()).is(id));
        return mongoTemplate.findOne(query, this.getEntityClass());
    }

    public void deleteById(String id) {
        Query query = new Query(Criteria.where(getIdProName()).is(id));
        mongoTemplate.remove(query, this.getEntityClass());
    }

    public void delete(Map<String, Object> queryMap) {
        Query query = getQuery(queryMap);
        mongoTemplate.remove(query, getEntityClass());
    }

    public List<T> selectList(Map<String, Object> queryMap) {
        Query query = getQuery(queryMap);
        return mongoTemplate.find(query, getEntityClass());
    }

    public List<T> searchList(Query query) {
        return mongoTemplate.find(query, getEntityClass());
    }

    public void update(Map<String, Object> queryMap, Map<String, Object> updateMap) {
        Query query = getQuery(queryMap);
        update(query, updateMap);
    }

    public void update(Query query, Map<String, Object> updateMap) {
        Update update = getUpdate(updateMap);
        mongoTemplate.updateMulti(query, update, getEntityClass());
    }

    public T increase(Map<String, Object> queryMap, Map<String, Number> incrMap) {
        Query query = getQuery(queryMap);
        Update update = new Update();
        for (Entry<String, Number> entry : incrMap.entrySet()) {
            update.inc(entry.getKey(), entry.getValue());
        }
        FindAndModifyOptions options = new FindAndModifyOptions();
        options.returnNew(true);
        return mongoTemplate.findAndModify(query, update, options, getEntityClass());
    }

    public long count(Query query) {
        return mongoTemplate.count(query, getEntityClass());
    }

    public T selectAndUpdate(Map<String, Object> queryObject, Map<String, Object> updateObject) {
        Query query = getQuery(queryObject);
        Update update = getUpdate(updateObject);
        return mongoTemplate.findAndModify(query, update, getEntityClass());
    }

    public void save(T bean) {
        mongoTemplate.save(bean);
    }

    public void insert(T bean) {
        mongoTemplate.insert(bean);
    }

    public void insertList(List<T> beans) {
        mongoTemplate.insertAll(beans);
    }

    /**
     * 
     * 工具类
     * 
     * @param map
     *            查询条件键值对
     * @return
     */
    public Query getQuery(Map<String, Object> map) {
        Query query = new Query();
        if (map == null || map.size() == 0) {
            return query;
        }
        Iterator<String> it = map.keySet().iterator();
        while (it.hasNext()) {
            String key = it.next();
            Object value = map.get(key);
            if (value != null) {
                Criteria criteria = Criteria.where(key).is(map.get(key));
                query.addCriteria(criteria);
            }
        }
        return query;
    }

    /**
     * 
     * 工具类
     * 
     * @param map
     *            查询条件键值对
     * @return
     */
    private Update getUpdate(Map<String, Object> map) {
        Update update = new Update();
        if (map == null) {
            return update;
        }
        Iterator<String> it = map.keySet().iterator();
        while (it.hasNext()) {
            String key = it.next();
            Object value = map.get(key);
            if (value != null) {
                update.set(key, map.get(key));
            }
        }
        return update;
    }
}
